#include "action.h"
#include "utils.h"
#include "config.h"

#ifdef __cplusplus
extern "C" {
#endif

/*********************| config |*********************/
CS_BUF_DECLAR(ACTION_BUF_SIZE, action_t)
CS_BUF_DECLAR(ACTION_EFF_BUF_SIZE, action_eff_t)
/*********************| structure |*********************/
struct acforflag_t {
	const int	ntime;
	action_handle	func;
	void* 		flag;
	uint32_t	interval;
	int32_t		sinterval;
};

struct aceffforflag_t {
	action_eff_handle	ufunc;
	void* 			uflag;
};

/*********************| static funcions |*********************/

static void aclist_free_fun(void* pdata)
{
	action_list_t* plist = (action_list_t*)pdata;
	list_clear(&plist->acs, (free_node_data)action_buf_return);
	free(plist);
}

static int action_foreach(void** datare, void* ctlflag)
{
	action_t* pac = (action_t*)(*datare);
	struct acforflag_t* ctl = (struct acforflag_t*)ctlflag;
	if (ctl->ntime && ctl->interval && !(ctl->ntime % ctl->interval) && ctl->sinterval) {
		pac->con.data0 += ctl->sinterval;
		if (CON_SIGN_TRUE != CON_GET_AOR(pac->con.tAs)) {
			pac->con.data1 += ctl->sinterval;
		}
	}
	/* 控制触发次数 */
	if (!pac->nforever) {
		if (pac->ntime && ctl->func(pac, ctl->flag))
			--pac->ntime;
	} else {
		ctl->func(pac, ctl->flag);
	}
	return 1;
}

static int ac_foreachfunc(void** datare, void* ctlflag)
{
	action_list_t* acl = (action_list_t*)(*datare);
	struct acforflag_t* ctl = (struct acforflag_t*)ctlflag;
	ctl->interval = acl->interval;
	ctl->sinterval = acl->sinterval;
	list_foreach(&acl->acs, action_foreach, (void*)ctl);
	return 1;
}

static int action_copy_for(void** datare, void* ctlflag)
{
	action_t* src = (action_t*)(*datare);
	list_t* l = (list_t*)ctlflag;
	action_t* dst = action_buf_rent();
	if (dst) {
		memcpy(dst, src, sizeof(action_t));
		list_insert(l, (void*)dst, 0, 1);
		return 1;
	}
	return 0;
}

static int ac_bufcopy_for(void** datare, void* ctlflag)
{
	list_t* ac = (list_t*)ctlflag;
	action_list_t* src = (action_list_t*)(*datare);
	ZERO_MALLOC(dst, action_list_t);
	dst->interval = src->interval;
	dst->sinterval = src->sinterval;
	list_foreach(&src->acs, action_copy_for, (void*)(&dst->acs));
	list_insert(ac, (void*)dst, 0, 1);
	return 1;
}

static int action_eff_for(void** datare, void* ctl)
{
	action_eff_t* eff = (action_eff_t*)(*datare);
	struct aceffforflag_t* p = (struct aceffforflag_t*)ctl;
	if (eff->n) {
		--eff->n;
		p->ufunc(eff, p->uflag);
	}
	if (!eff->n) {
		action_eff_buf_return(eff);
		return 2;
	}
	return 1;
}

/*********************| extern functions |*********************/

CSB_DLL uint32_t actiondata_read(ac_t* pac, unsigned char* data, const int8_t typeoffset)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_RET(pac && data, CSBERR_PARAM, 0);
	uint32_t rlen = sizeof(uint32_t);
	uint32_t naclist = 0; // action list array num
	memcpy(&naclist, data, rlen);
	if (!naclist) return rlen;

	*pac = list_new();
	action_list_t* plist = NULL;
	uint32_t nread = rlen;
	action_t* ac = NULL;
	while (naclist > 0) {
		--naclist;
		plist = (action_list_t*)malloc(sizeof(action_list_t));
		memset(plist, 0, sizeof(action_list_t));
		list_insert(*pac, (void*)plist, 0, 1);
		nread = sizeof(action_list_t) - sizeof(list_t);
		memcpy(plist, data + rlen, nread);
		rlen += nread;
		memcpy(&nread, data +rlen, sizeof(uint32_t));
		rlen += sizeof(uint32_t);
		while (nread > 0) {
			--nread;
			ac = action_buf_rent();
			memcpy(ac, data + rlen, sizeof(action_t));
			if (ac->changetime < 1)
				ac->changetime = 1;
			ac->restype += typeoffset;
			rlen += sizeof(action_t);
			list_insert(&plist->acs, (void*)ac, 0, 1);
		}
	}
	return rlen;
}


CSB_DLL void ac_free(ac_t ac)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(ac, CSBERR_PARAM);
	list_free(ac, aclist_free_fun);
}


CSB_DLL void ac_foreach(ac_t ac, action_handle func, const int32_t ntime, void* flag)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(ac && func, CSBERR_PARAM);
	struct acforflag_t ctl = {ntime, func, flag, 0, 0};
	list_foreach(ac, ac_foreachfunc, &ctl);
}

CSB_DLL void action_buf_init() { CS_BUF_INIT(action_t); }

CSB_DLL void action_buf_end(bool force) { CS_BUF_END(action_t, force); }

CSB_DLL action_t* action_buf_rent()
{
	CS_BUF_RENT(action_t, ret);
	return ret;
}

CSB_DLL void action_buf_return(action_t* pac) { CS_BUF_RETURN(action_t, pac); }

CSB_DLL void action_eff_buf_init() { CS_BUF_INIT(action_eff_t); }

CSB_DLL void action_eff_buf_end(bool force) { CS_BUF_END(action_eff_t, force); }

CSB_DLL action_eff_t* action_eff_buf_rent()
{
	CS_BUF_RENT(action_eff_t, ret);
	return ret;
}

CSB_DLL void action_eff_buf_return(action_eff_t* pace) { CS_BUF_RETURN(action_eff_t, pace); }

CSB_DLL ac_t ac_buf_copy(const ac_t src)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_RET(src, CSBERR_PARAM, NULL);
	list_t* ret = list_new();
	list_foreach(src, ac_bufcopy_for,ret);
	return ret;
}


CSB_DLL void action_eff_list_clean(list_t* pl)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(pl, CSBERR_PARAM);
	list_clear(pl, (free_node_data)action_eff_buf_return);
}


CSB_DLL void action_eff_list_for(list_t* pl, action_eff_handle func, void* flag)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(pl && func, CSBERR_PARAM);
	struct aceffforflag_t tmp = {func, flag};
	list_foreach(pl, action_eff_for, (void*)(&tmp));
}

CSB_DLL action_eff_t* action_make_action_eff(const action_t* pac)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_RET(pac, CSBERR_PARAM, NULL);
	action_eff_t* ret = action_eff_buf_rent();
	if (ret) {
		// 根据变化条件，变化方式，变化结果进行计算
		ret->type = pac->restype;
		ret->ressign = pac->conressign;
		ret->mesign = pac->conmesign;
		switch (ret->mesign) {
		case CON_ME_FIXED:
			ret->data = pac->resdata;
			if (CON_RES_TO == ret->ressign){
				ret->n = 1;
			} else {
				ret->n = pac->changetime;
			}
			break;
		case CON_ME_DRATIO:
			ret->n = pac->changetime;
			if (CON_RES_TO == ret->ressign){
				ret->data = pac->resdata;
			} else {
				ret->data = pac->resdata / ret->n;
			}
			break;
		case CON_ME_SIN:
			break;
		}
	}
	return ret;
}

#ifdef __cplusplus
}// end of extern C
#endif
